<template>
<div 
    class="touch-tab-cp"
    ref="TabTabEl"
    :style="{
        '--touchTabSlotLength':getSlots().length,
    }">
    <div 
        ref="ContainerEl"
        class="touch-tag-container">
        <slot></slot>
    </div>
</div>
</template>
<script>
/*
 自定义touchTab组件
 */
import {touchEvent} from "@/common/ElEvent";
export default {
    name:'TouchTab',
    data() {
        this.timer;
        this.touched = false;  //正在滑动
        this.speed = 0;  //移动速度
        this.translateX = 0;  //容器的偏移量
        return {
            activeIndex:0,  //当前显示的子元素
        };
    },
    watch:{
        activeIndex:{  //当前选项发生变化时向外部暴露
            handler(newVlaue){
                this.$emit('onChange',newVlaue);
            },
            immediate:true,
        },
    },
    mounted(){
        //添加滑动事件
        touchEvent({
            target:this.getTabTabEl(),
            hasSpeedX:true,
            touchFn:(data)=>{  //滑动时执行
                this.touched = true;
                let clientXDiff = data.newX - data.oldX;
                this.setEltransform(this.translateX + clientXDiff);
            },
            speedFn:(data)=>{  //滑动完后执行
                this.touched = false;
                this.speed = data.speedX;
                this.setUpTransition(true);
                this.inferIndex();
            },
        });
        //添加移动端事件
        this.getTabTabEl().addEventListener('touchstart',()=>{
            this.setUpTransition(false);
        });
        //添加pc端事件
        this.getTabTabEl().addEventListener('mousedown',()=>{
            this.setUpTransition(false);
        });
        //添加动画结束事件
        this.getContainerEl().addEventListener('transitionend', ()=>{
            if(!this.isActive()) return;
            if(this.touched) return;
            this.computeStyle();
        });
        window.addEventListener("resize",()=>{
            if(!this.isActive()) return;
            if(this.touched) return;
            this.computeStyle();
        });
        this.timer = setInterval(() => {
            if(!this.isActive()) return;
            if(this.touched) return;
            this.computeStyle();
        }, 3000);
        //计算样式
        this.computeStyle();
    },
    updated(){
        this.computeStyle();
    },
    methods:{
        isActive(){  //是否是当前活动的组件
            const el = this.$el;
            if(!el) return false;
            return !!(el.clientWidth || el.clientHeight);
        },
        getSlots(){  //获取slot，过滤空的元素
            if(!this.$slots.default) return [];
            return this.$slots.default.filter(item=>{
                return item.tag;
            });
        },
        getTabTabEl(){  //获取该组件元素
            return this.$refs.TabTabEl;
        },
        getContainerEl(){  //获取容器元素
            return this.$refs.ContainerEl;
        },
        getContainerChildEls(){  //获取容器子元素
            return this.getSlots();
        },
        setEltransform(value){  //写入移动位置
            if(!this.isActive()) return;  //表示此时元素已经消失
            this.translateX = value;
            const containerEl = this.getContainerEl();
            let transform = `translateX(${value}px) translateZ(0px)`;
            if(containerEl.style.transform == transform) return;
            containerEl.style.transform = transform;
        },
        inferIndex(){  //推断索引位置
            let itemWidth = this.getTabTabEl().clientWidth;
            let widthDiff = itemWidth*this.activeIndex + this.translateX;  //计算宽度差
            let testSpeed = this.speed>1.5;  //验证速度
            this.speed = 0;  //及时清空，防止重复调用
            if(widthDiff == 0) {  //表示并没有宽度差，不推断
                return;
            }
            let widthDiffAbs = Math.abs(widthDiff);  //差值绝对值
            let direction = widthDiff>0?'left':'right';  //滑动的方向
            switch(true){
                case widthDiffAbs>(itemWidth/2) || testSpeed:  //如果滑动超过了一个子元素的一半 或者 速度超过了一定值
                    this.setActiveEl(
                        direction=='right'?this.activeIndex+1:this.activeIndex-1,
                    );
                    break;
                default:
                    this.setActiveEl(this.activeIndex);
            }
        },
        setActiveEl(index){  //设置当前显示的item索引，并显示该item(可外部调用)
            const childEls = this.getContainerChildEls();
            const tabEl = this.getTabTabEl();
            if(!childEls || childEls.length == 0 || !tabEl) return;
            switch(true){
                case index<=0:
                    this.activeIndex = 0;
                    break;
                case index>(childEls.length-1):
                    this.activeIndex = childEls.length-1;
                    break;
                default:
                    this.activeIndex = index;
            }
            this.computeHeight();
            let newTranslateX = (- tabEl.getBoundingClientRect().width * this.activeIndex);
            this.setUpTransition(true);
            this.setEltransform(newTranslateX);
        },
        computeStyle(){  //计算样式
            this.computeWidth();
            this.computeHeight();
        },
        computeWidth(){  //计算每个子元素的宽度，使每个与总元素等宽  （可外部调用）
            const tabEl = this.getTabTabEl();
            if(!tabEl) return;
            tabEl.style.setProperty(
                '--touchTabSlotLength',
                this.getSlots().length,
            );
        },
        computeHeight(index){  //计算高度，使总元素与当前显示的子元素等高  （可外部调用）
            index = index || this.activeIndex;  //可以指定是哪一项
            const childEls = this.getContainerChildEls();
            const tabEl = this.getTabTabEl();
            if(!childEls || !tabEl) return;
            if(!this.isActive()) return;  //表示该元素被隐藏
            if(!childEls[index]) return;
            let elData = childEls[index].elm.getBoundingClientRect();
            if(elData.height == 0) return;
            let height = elData.height + 'px';
            if(tabEl.style.height == height) return;
            tabEl.style.height = height;
        },
        setUpTransition(state=true){  //设置是否开启动画
            let el = this.getContainerEl();
            if(!el) return;
            if(state){
                el.style.transitionDuration = '300ms';
            }else{
                el.style.transitionDuration = '0ms';
            }
        },
    },
    destroyed(){
        clearInterval(this.timer);
    },
}
</script>
<style lang="scss" scoped>
.touch-tab-cp{
    width: 100%;
    margin: 0 auto;
    height: fit-content;
    overflow: hidden;
    >.touch-tag-container{
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;  //设置不可选取
        width:calc(var(--touchTabSlotLength) * 100%) !important;
        display: grid;
        grid-template-columns: repeat(var(--touchTabSlotLength),1fr);
        transition: transform 0.3s;
        animation-timing-function:cubic-bezier(0, 0.63, 0.58, 1);
        transition-duration: 0ms;
        >*{
            height: fit-content;
        }
    }
}
</style>